#include <string>
#include <vector>
#include <unordered_map>
#include <queue>
#include <pthread.h>
#include "Task.hpp"

using namespace std;

//为什么提供单例的接口和对应指针要设为静态的？ 
//--> 因为静态的可以在程序加载后可以“看到”(可以实验证明) ；若是非静态的，类对象不创建，相应接口就看不到！（通过类名看到了也不能用，因为没有this指针！）
//--> 静态成员只能访问静态成员，“和不需要this指针作为参数的函数，也就是构造”， 所以配套要设为静态的（包括维护安全的锁）！

static const int DefaultThreadNum = 5;

class ThreadData
{
public:
    ThreadData(int no = 0,const string& name = "thread-")
    :_name(name + to_string(no)), _tid(0)
    {       
    }
    string _name;
    pthread_t _tid;
};

template<class T>
class ThreadPool
{

//封装加锁解锁和休眠唤醒
private:
    void Lock()
    {
        pthread_mutex_lock(&_lock);
    }

    void UnLock()
    {
        pthread_mutex_unlock(&_lock);
    }

    void WakeUp()
    {
        pthread_cond_signal(&_cond);
    }

    void ThreadSleep()
    {
        pthread_cond_wait(&_cond,&_lock);
    }

    bool IsQueueEmpty()
    {
        return _tasks.empty();
    }

    string GetThreadName(pthread_t tid)
    {
        return _hashOfTd[tid]._name;
    }

public:

    static ThreadPool<T>* GetInstance()
    {
        if(_tp_pointer == nullptr)      //双重if判断 --> 保证安全直接加锁就行，双重if是为了避免不必要的锁竞争而提高性能！
        {
            pthread_mutex_lock(&_tp_p_lock);
            if(_tp_pointer == nullptr)
            {
                cout << "create a singleton..." << endl;
                _tp_pointer = new ThreadPool<T>();      //理解本质：看似可以访问 类内成员构造 是因为 构造不需要this指针！
            }  
            pthread_mutex_unlock(&_tp_p_lock);          
        }

        return _tp_pointer;
    }

    static void* HandleTask(void* arg)      //静态成员函数无法直接访问 “除构造外” 的类内成员，所以传this指针！
    {
        ThreadPool<T>* tp = static_cast<ThreadPool<T>*>(arg);
        while(1)
        {
            //1.获取任务
            tp->Lock();
            while(tp->IsQueueEmpty())   //防误唤醒！在这加锁就行，不要再在Pop中加锁了-->否则就卡住了(因为此时状态是持有锁而又申请锁！)
            {
                tp->ThreadSleep();
            }
            Task t = tp->Pop();
            tp->UnLock();

            //2.加工处理任务
            t();        
        }

        return nullptr;
    }

    //将创建一批线程的工作封装
    void Start()
    {  
        for(int i = 0; i < DefaultThreadNum; i++)
        {
            ThreadData td = ThreadData(i);
            pthread_create(&td._tid,nullptr,HandleTask,this);
            _hashOfTd[td._tid] = td;
        }
    }

    void Push(const T& in)
    {
        Lock();
        _tasks.push(in);
        WakeUp();
        UnLock();
    }

    T Pop()     
    {
        T t = _tasks.front();
        _tasks.pop();
        return t;
    }

private:
    ThreadPool(int threadnum = DefaultThreadNum)
    {
        //_tds = vector<ThreadData>(threadnum);
        pthread_mutex_init(&_lock,nullptr);
        pthread_cond_init(&_cond,nullptr);
    }
    ThreadPool(const ThreadPool<T>& tp) = delete;
    void operator=(const ThreadPool<T>& tp) = delete;
    ~ThreadPool()
    {
        pthread_mutex_destroy(&_lock);
        pthread_cond_destroy(&_cond);
    }

private:
    //vector<ThreadData> _tds;
    static ThreadPool<T>* _tp_pointer;         //配合获取单例的静态指针
    static pthread_mutex_t _tp_p_lock;         //保证获取单例的线程安全

    unordered_map<pthread_t,ThreadData> _hashOfTd;      //便于获取线程信息
    queue<T> _tasks;
    pthread_mutex_t _lock;
    pthread_cond_t _cond;
};

template<class T>
ThreadPool<T>* ThreadPool<T>::_tp_pointer = nullptr;

template<class T>
pthread_mutex_t ThreadPool<T>::_tp_p_lock = PTHREAD_MUTEX_INITIALIZER;
